<template>
  <div class="czr-form-column-upload-com"
       :class="{
         'czr-form-column-upload-com_view': isValue($attrs.disabled) ? $attrs.disabled : (isLimitCpt || isViewCpt),
         'czr-form-column-upload-com_list': layout === 'list',
         'czr-form-column-upload-com_card': layout === 'card',
         'czr-form-column-upload-com_limit-no-upload': isLimitCpt && limitNoUpload !== false
       }"
       v-loading="state.loading"
       :element-loading-background="state.elementLoadingBackground">
    <el-upload
        class="el-upload-com"
        ref="ref_upload"
        v-bind="$attrs"
        :file-list="state.paramVal"
        action="#"
        :list-type="layout === 'card' ? 'picture-card' : 'text'"
        :http-request="handleRequest"
        :before-upload="handleBeforeUpload"
        :accept="acceptTypeCpt"
        :limit="limit > 0 ? limit : null"
        :on-remove="handleRemove"
        :disabled="isValue($attrs.disabled) ? $attrs.disabled : (isLimitCpt || isViewCpt)"
    >
      <el-tooltip :content="acceptTooltipCpt" placement="top" popper-class="upload-tooltip-popper">
        <template v-if="layout === 'card'">
          <div class="upload-layout-card __hover" :class="{'limit-disabled': isLimitCpt || (isViewCpt && state.paramVal.length === 0)}">
            <SvgIcon name="add" color="#0062E9" size="24"/>
            <template v-if="title">
              <div>{{title}}</div>
            </template>
            <template v-else>
              <div>选择{{acceptTypeFormatCpt}}</div>
              <div v-if="limit > 0">(最多{{ limit }}个)</div>
            </template>
          </div>
        </template>
        <template v-else>
          <div class="upload-layout-list_button" :class="{'limit-disabled': isLimitCpt|| (isViewCpt && state.paramVal.length === 0)}">
            <SvgIcon name="add" color="#ffffff" size="14"/>
            <template v-if="title">
              {{title}}
            </template>
            <template v-else>
              选择{{acceptTypeFormatCpt}}
              <template v-if="limit > 0">(最多{{ limit }}个)</template>
            </template>
          </div>
        </template>
      </el-tooltip>
      <template #file="{file}">
        <template v-if="layout === 'card'">
          <el-tooltip placement="top" :content="file[nameKey] ?? file[urlKey]" :disabled="true">
            <div class="upload-layout-card_item" :class="{'item-view': isViewCpt || !delRule(file)}" @mouseenter="file.hover = true" @mouseleave="file.hover = false">
              <template v-if="validImgByUrl(file[urlKey])">
                <img class="img __hover" :src="file[urlKey]" @click="viewImg(file[urlKey])"/>
              </template>
              <template v-else-if="validVideoByUrl(file[urlKey])">
                <video class="video __hover" controls :src="file[urlKey]"/>
              </template>
              <template v-else>
                <img class="file __hover" :src="getFileImgByUrl(file[urlKey])" @click="downloadFileByUrl(file[urlKey], file[nameKey])"/>
              </template>
              <img class="del __hover" src="../imgs/file-del.png" v-if="file.hover && !isViewCpt && delRule(file)" @click.stop="ref_upload.handleRemove(file)"/>
            </div>
          </el-tooltip>
        </template>
        <template v-else>
          <div class="upload-layout-list_item __hover" :class="{'item-view': isViewCpt || !delRule(file)}" @click="validImgByUrl(file[urlKey]) ? viewImg(file[urlKey]) : downloadFileByUrl(file[urlKey], file[nameKey])">
            <img class="file-type-img" :src="getFileImgByUrl(file[urlKey])"/>
            <CzrEllipsis v-if="file[nameKey] ?? file[urlKey]" class="label" :value="file[nameKey] ?? file[urlKey]"/>
            <SvgIcon v-if="!isViewCpt && delRule(file)" class="close" name="close_3" size="12" @click.stop="ref_upload.handleRemove(file)"/>
          </div>
        </template>
      </template>
    </el-upload>
    <el-image-viewer
        v-if="state.currentImg.show"
        :zoom-rate="2"
        :max-scale="10"
        :min-scale="0.2"
        :hide-on-click-modal="true"
        :url-list="[state.currentImg.url]"
        :initial-index="0"
        @close="imageClose"
        :teleported="true"
        :crossorigin="null"
    />
  </div>
</template>

<script setup lang="ts">
import {
  defineComponent,
  computed,
  onMounted,
  ref,
  reactive,
  watch,
  getCurrentInstance,
  ComponentInternalInstance,
  toRefs,
  nextTick, onBeforeMount, inject
} from 'vue'
import {useRouter, useRoute} from 'vue-router'
import {ElMessage} from "element-plus";
import FileDefaultImg from '../imgs/file-type/file-type_default.png'
import FilePDFImg from '../imgs/file-type/file-type_pdf.png'
import FilePPTImg from '../imgs/file-type/file-type_ppt.png'
import FileRARImg from '../imgs/file-type/file-type_rar.png'
import FileTXTImg from '../imgs/file-type/file-type_txt.png'
import FileWORDImg from '../imgs/file-type/file-type_word.png'
import FileEXCELImg from '../imgs/file-type/file-type_excel.png'
import {isValue} from "@/utils/czr-util";
// import {frontUploadFile} from "@/api/modules/manage/global";

const emit = defineEmits(['emitParam'])
const props = defineProps({
  param: {},
  label: {},
  limit: {
    default: 0
  },
  type: {default: 'all', validator(val: string) {
      return ['all', 'img', 'file'].includes(val)
    }},
  layout: {default: 'list', validator(val: string) {
      return ['list', 'card'].includes(val)
    }},
  acceptType: {default: '', type: String},
  acceptMax: {default: 0, type: Number},
  acceptFunc: {default: () => (options) => {}},
  view: {default: null},
  delRule: {default: () => () => false},
  cardWidth: {default: '147px'},
  cardHeight: {default: '128px'},
  urlKey: {default: 'url'},
  nameKey: {default: 'name'},
  limitNoUpload: {default: false},
  title: {}
})
const state = reactive({
  paramVal: <any>props.param,
  loading: false,
  elementLoadingBackground: inject('element-loading-background', null),
  currentImg: {
    show: false,
    url: ''
  },
  formView: inject('form-view', false),
  config: {
    fileMax: 50,
    fileType: '.doc,.docx,.ppt,.pptx,.pdf,.xls,.xlsx,.txt,.rar,.zip',
    imgMax: 50,
    imgType: '.jpg,.jpeg,.png,.gif,.svg,.bmp,.webp',
  }
})
watch(() => state.paramVal, (n) => {
  emit('emitParam', n)
})
watch(() => props.param, (n) => {
  state.paramVal = n
})
const isViewCpt = computed(() => {
  return isValue(props.view) ? props.view : state.formView
})
const ref_upload = ref()
const validImgByUrl = (url) => {
  if (url) {
    const imgList = ['bmp', 'jpg','jpeg', 'png', 'tif', 'gif', 'pcx', 'tga', 'exif', 'fpx', 'svg', 'psd', 'cdr', 'pcd', 'dxf', 'ufo', 'eps', 'ai', 'raw', 'WMF', 'webp', 'avif', 'apng', 'jfif'];
    //进行图片匹配
    let result = [...imgList.map(v => v.toLowerCase()), ...imgList.map(v => v.toUpperCase())].some((t) => url.includes('.' + t)) || url.includes('/ngx/proxy')  || url.includes('/pic?');
    return result
  }
  return false
}
const validVideoByUrl = (url) => {
  if (url) {
    const videoList = ['mp4'];
    //进行图片匹配
    let result = [...videoList.map(v => v.toLowerCase()), ...videoList.map(v => v.toUpperCase())].some((t) => url.includes('.' + t));
    return result
  }
  return false
}
const acceptTypeCpt = computed(() => {
  let str = ''
  if (isValue(props.acceptType)) {
    str += props.acceptType
  } else {
    if (props.type === 'all') {
      str += state.config.imgType
      str += ',' + state.config.fileType
    } else if (props.type === 'img') {
      str += state.config.imgType
    } else if (props.type === 'file') {
      str += state.config.fileType
    }
  }
  return str
})
const acceptTypeFormatCpt = computed(() => {
  let str = ''
  if (isValue(props.acceptType)) {
    str += `自定义文件`
  } else {
    if (props.type === 'all') {
      str += `图片、文件`
    } else if (props.type === 'img') {
      str += `图片`
    } else if (props.type === 'file') {
      str += `文件`
    }
  }
  return str
})
const acceptTooltipCpt = computed(() => {
  let str = ''
  if (isValue(props.acceptType)) {
    str += `只支持大小在0~${props.acceptMax}M内，格式为${props.acceptType}的自定义文件`
  } else {
    if (props.type === 'all') {
      str += `只支持大小在0~${state.config.imgMax}M内，格式为${state.config.imgType}的图片，`
      str += `或大小在0~${state.config.fileMax}M内，格式为${state.config.fileType}的文件`
    } else if (props.type === 'img') {
      str += `只支持大小在0~${state.config.imgMax}M内，格式为${state.config.imgType}的图片`
    } else if (props.type === 'file') {
      str += `只支持大小在0~${state.config.fileMax}M内，格式为${state.config.fileType}的文件`
    }
  }
  if (isLimitCpt.value) {
    str = `最多上传${props.limit}个${acceptTypeFormatCpt.value}`
  }
  return str
})
const isLimitCpt = computed(() => {
  return props.limit > 0 && props.limit <= state.paramVal.length
})
const handleBeforeUpload = (file) => {
  if (isValue(props.acceptType)) {
    if (file.size / (1024 * 1024) > props.acceptMax) {
      ElMessage.warning(`自定义文件大小不可超过${props.acceptMax}M`)
      return false
    } else if (!props.acceptType.split(',').some(v => file.name.includes(v))) {
      ElMessage.warning(`自定义文件类型仅支持${props.acceptType}`)
      return false
    }
  } else {
    if (props.type === 'img') {
      if (file.size / (1024 * 1024) > state.config.imgMax) {
        ElMessage.warning(`图片大小不可超过${state.config.imgMax}M`)
        return false
      } else if (!state.config.imgType.split(',').some(v => file.name.includes(v))) {
        ElMessage.warning(`图片类型仅支持${state.config.imgType}`)
        return false
      }
    } else if (props.type === 'file') {
      if (file.size / (1024 * 1024) > state.config.fileMax) {
        ElMessage.warning(`文件大小不可超过${state.config.fileMax}M`)
        return false
      } else if (!state.config.fileType.split(',').some(v => file.name.includes(v))) {
        ElMessage.warning(`文件类型仅支持${state.config.fileType}`)
        return false
      }
    } else if (props.type === 'all') {
      if (!acceptTypeCpt.value.split(',').some(v => file.name.includes(v))) {
        ElMessage.warning(`文件或图片类型仅支持${acceptTypeCpt.value}`)
        return false
      } else {
        if (state.config.imgType.split(',').some(v => file.name.includes(v))) {
          if (file.size / (1024 * 1024) > state.config.imgMax) {
            ElMessage.warning(`图片大小不可超过${state.config.imgMax}M`)
            return false
          }
        } else if (state.config.fileType.split(',').some(v => file.name.includes(v))) {
          if (file.size / (1024 * 1024) > state.config.fileMax) {
            ElMessage.warning(`文件大小不可超过${state.config.fileMax}M`)
            return false
          }
        }
      }
    }
  }
  return file
}
const handleRequest = async (options) => {
  state.loading = true
  if (isValue(props.acceptType)) {
    const result: any = await props.acceptFunc(options)
    if (result?.[props.urlKey] && result?.[props.nameKey]) {
      state.paramVal = [...state.paramVal, result]
    } else {
      state.paramVal = [...state.paramVal]
    }
    state.loading = false
  } else if ([...state.config.imgType.split(','), ...state.config.fileType.split(',')].some(v => options.file.name.includes(v))) {
    const formData = new FormData();
    formData.append("file", options.file);
    // frontUploadFile(formData).then(res => {
    //   state.paramVal = [...state.paramVal, {
    //     [props.urlKey]: res.data.path,
    //     [props.nameKey]: res.data.filename.replace(/,/g, '_')
    //   }]
    //   state.loading = false
    // }).catch(() => {
    //   // state.loading = false
    // })
  }
}
const fileTypeMapper = new Map([
  ['doc', FileWORDImg],
  ['docx', FileWORDImg],
  ['ppt', FilePPTImg],
  ['pptx', FilePPTImg],
  ['pdf', FilePDFImg],
  ['xls', FileEXCELImg],
  ['xlsx', FileEXCELImg],
  ['txt', FileTXTImg],
  ['rar', FileRARImg],
  ['zip', FileRARImg],
])
const getFileImgByUrl = (url) => {
  if (url) {
    const regex = /\.([^.]*)$/;
    const match = url.match(regex);
    const t = match ? match[1] : '';
    if (t && fileTypeMapper.has(t)) {
      return fileTypeMapper.get(t)
    }
  }
  return FileDefaultImg
}
const handleRemove = (file, files) => {
  state.paramVal = files
}
const downloadFileByUrl = (url, name) => {
  ElMessage.info('开始下载！')
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'blob';
  xhr.onload = function () {
    if (xhr.status === 200) {
      const blob = xhr.response;
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = name || 'default';
      a.click();
      ElMessage.success('下载成功！')
      window.URL.revokeObjectURL(url);
    }
  };
  xhr.send();
}
const viewImg = (url) => {
  state.currentImg.url = url
  state.currentImg.show = true
}
const imageClose = () => {
  state.currentImg.show = false
  state.currentImg.url = ''
}
</script>

<style scoped lang="scss">
.czr-form-column-upload-com {
  $uploadWidth: v-bind(cardWidth);
  $uploadHeight: v-bind(cardHeight);
  width: 100%;
  position: relative;
  .el-upload-com {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    :deep(.el-upload) {
      .upload-layout-list_button {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0 6px;
        background-color: var(--czr-main-color);
        border-radius: 4px;
        font-size: 14px;
        font-family: Microsoft YaHei;
        font-weight: 400;
        color: #FFFFFF;
        .svg-icon {
          margin-right: 7px;
        }
        &.limit-disabled {
          cursor: no-drop;
          opacity: 0.5;
        }
      }

      .upload-layout-card {
        width: 100%;
        height: 100%;
        display: flex;
        flex-direction: column;
        line-height: 1;
        align-items: center;
        justify-content: center;
        background-color: rgba(46, 129, 255, 0.04);
        .svg-icon {
          margin-bottom: 10px;
          opacity: 0.5;
        }
        > div {
          font-size: 14px;
          font-family: PingFang SC-Regular, PingFang SC;
          font-weight: 400;
          color: rgba(0,98,233,0.5);
        }
        &.limit-disabled {
          cursor: no-drop;
          opacity: 0.5;
        }
      }
    }
    :deep(.el-upload-list) {
      margin: 0;
      .el-upload-list__item {
        transition: none;
        .upload-layout-list_item {
          display: flex;
          align-items: center;
          padding: 0 6px;
          .file-type-img {
            width: 14px;
            margin: 0 6px 0 6px;
          }
          .label {
            width: calc(100% - 6px - 6px - 14px - 30px);
          }
          .close {
            margin-left: auto;
          }
          &.item-view {
            .label {
              width: calc(100% - 6px - 6px - 14px);
            }
          }
        }
        .upload-layout-card_item {
          width: 100%;
          height: 100%;
          position: relative;
          .img {
            width: 100%;
            height: 100%;
          }
          .video {
            width: 100%;
            height: 100%;
            object-fit: fill;
          }
          .file {
            width: 100%;
            height: 100%;
          }
          .del {
            position: absolute;
            top: 0;
            right: 0;
            z-index: 2;
            width: 20px;
            height: 20px;
          }
        }
      }
    }
  }
  &.czr-form-column-upload-com_view, &.czr-form-column-upload-com_limit-no-upload {
    .el-upload-com {
      :deep(.el-upload) {
        display: none;
      }
    }
  }
  &.czr-form-column-upload-com_card {
    .el-upload-com {
      :deep(.el-upload) {
        width: $uploadWidth;
        height: $uploadHeight;
      }
      :deep(.el-upload-list) {
        .el-upload-list__item {
          width: $uploadWidth;
          height: $uploadHeight;
        }
      }
    }
  }
}
</style>
